package com.xnf.article.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xnf.article.mapper.ApArticleMapper;
import com.xnf.article.service.ApArticleService;
import com.xnf.common.constants.article.ArticleConstants;
import com.xnf.model.article.dtos.ArticleHomeDto;
import com.xnf.model.article.mess.ArticleVisitStreamMess;
import com.xnf.model.article.pojos.ApArticle;
import com.xnf.model.article.vo.HotArticleVo;
import com.xnf.model.common.dtos.ResponseResult;
import com.xnf.model.common.enums.AppHttpCodeEnum;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;


@Service
public class ApArticleServiceImpl extends ServiceImpl<ApArticleMapper, ApArticle> implements ApArticleService {
    // 单页最大加载的数字
    private final static short MAX_PAGE_SIZE = 50;
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private ApArticleMapper apArticleMapper;

    @Value("${fdfs.url}")
    private String fileServerUrl;

    /**
     * 根据参数加载文章列表
     *
     * @param loadtype 1为加载更多  2为加载最新
     * @param dto
     * @return
     */
    @Override
    public ResponseResult load(ArticleHomeDto dto, Short loadtype) {
        if (dto == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        Integer size = dto.getSize();
        if (size == null || size == 0) {
            size = 10;
        }
        Math.min(size, 50);
        dto.setSize(size);
        if (!loadtype.equals(ArticleConstants.LOADTYPE_LOAD_MORE) && !loadtype.equals(ArticleConstants.LOADTYPE_LOAD_NEW)){
            loadtype = ArticleConstants.LOADTYPE_LOAD_MORE;
        }
        //文章频道校验
        if(StringUtils.isEmpty(dto.getTag())){
            dto.setTag(ArticleConstants.DEFAULT_TAG);

        }
        if (dto.getMaxBehotTime() == null){
            dto.setMaxBehotTime(new Date());
        }
        if (dto.getMinBehotTime() == null){
            dto.setMinBehotTime(new Date());
        }

        List<ApArticle> apArticles = apArticleMapper.loadArticleList(dto, loadtype);
        ResponseResult responseResult = ResponseResult.okResult(apArticles);
        responseResult.setHost(fileServerUrl);
        return responseResult;
    }

    /**
     * 重新计算文章的分值
     *
     * @param mess
     */
    @Override
    public void updateApArticle(ArticleVisitStreamMess mess) {
        ApArticle apArticle = apArticleMapper.selectById(mess.getArticleId());
        if (apArticle == null) {
            throw new RuntimeException("当前文章不存在");
        }
        //2.修改文章
        //阅读数量
        int view = (int) (apArticle.getViews() == null ? mess.getView() : mess.getView() + apArticle.getViews());
        apArticle.setViews(view);
        //点赞数量
        int like = (int) (apArticle.getLikes() == null ? mess.getLike() : mess.getLike() + apArticle.getLikes());
        apArticle.setLikes(like);
        //评论数量
        int comment = (int) (apArticle.getComment() == null ? mess.getComment() : mess.getComment() + apArticle.getComment());
        apArticle.setComment(comment);
        //收藏数量
        int collection = (int) (apArticle.getCollection() == null ? mess.getCollect() : mess.getCollect() + apArticle.getCollection());
        apArticle.setCollection(collection);
        //修改数据
        updateById(apArticle);

        //3.计算文章的分值  权重*3
        Integer score = computeScore(apArticle);
        score = score * 3;
        HotArticleVo hotArticleVo = new HotArticleVo();
        BeanUtils.copyProperties(apArticle, hotArticleVo);
        // hotArticleVo.setScore(score);

        String articleListStr = redisTemplate.opsForValue().get(ArticleConstants.HOT_ARTICLE_FIRST_PAGE + "_" + apArticle.getChannelId());
        updateArticleCache(apArticle, score, articleListStr);
    }

    @Override
    public ResponseResult load2(Short loadType, ArticleHomeDto dto, boolean firstPage) {
        if (firstPage) {
            String jsonStr = redisTemplate.opsForValue().get(ArticleConstants.HOT_ARTICLE_FIRST_PAGE + dto.getTag());
            if (StringUtils.isNotBlank(jsonStr)) {
                List<HotArticleVo> hotArticleVoList = JSON.parseArray(jsonStr, HotArticleVo.class);
                if (!hotArticleVoList.isEmpty() && hotArticleVoList.size() > 0) {
                    ResponseResult responseResult = ResponseResult.okResult(hotArticleVoList);
                    responseResult.setHost(fileServerUrl);
                    return responseResult;
                }
            }
        }
        return load(dto, loadType);
    }

    @Override
    public ResponseResult updateApArticleLVC(String type, Long articleId) {
        if (articleId == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        ApArticle apArticle = getById(articleId);
        if (apArticle == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        try {
            apArticleMapper.updateApArticle(type,articleId);

            return ResponseResult.errorResult(AppHttpCodeEnum.SUCCESS);
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR);
        }
    }

    /**
     * 更新文章的分值
     *
     * @param apArticle
     * @param score
     * @param articleListStr
     */
    private void updateArticleCache(ApArticle apArticle, Integer score, String articleListStr) {
        boolean flag = false;
        if (StringUtils.isNotBlank(articleListStr)) {
            List<HotArticleVo> hotArticleVos = JSON.parseArray(articleListStr, HotArticleVo.class);
            //4.1.如果当前缓存中有当前文章，则更新分值
            for (HotArticleVo hotArticleVo : hotArticleVos) {
                if (hotArticleVo.getId().equals(apArticle.getId())) {
                    hotArticleVo.setScore(score);
                    flag = true;
                    break;
                }
            }
            if (!flag) {
                //4.2.如果缓存中没有当前文章，获取缓存中分值较低的数据进行对比
                if (hotArticleVos.size() >= 30) {
                    //排序
                    hotArticleVos = hotArticleVos.stream().sorted(Comparator.comparing(HotArticleVo::getScore).reversed()).collect(Collectors.toList());
                    HotArticleVo hotArticleVo = hotArticleVos.get(hotArticleVos.size() - 1);
                    if (hotArticleVo.getScore() < score) {
                        hotArticleVos.remove(hotArticleVo);
                        HotArticleVo newHotArticleVo = new HotArticleVo();
                        BeanUtils.copyProperties(apArticle, newHotArticleVo);
                        newHotArticleVo.setScore(score);
                        hotArticleVos.add(newHotArticleVo);
                    }
                } else {
                    HotArticleVo newHotArticleVo = new HotArticleVo();
                    BeanUtils.copyProperties(apArticle, newHotArticleVo);
                    newHotArticleVo.setScore(score);
                    hotArticleVos.add(newHotArticleVo);
                }
            }
            //更新数据到缓存中
            redisTemplate.opsForValue().set(ArticleConstants.HOT_ARTICLE_FIRST_PAGE + apArticle.getChannelId(),
                    JSON.toJSONString(hotArticleVos));
        }
    }

    private Integer computeScore(ApArticle apArticle) {
        Integer score = 0;
        if (apArticle.getLikes() != null) {
            score += apArticle.getLikes() * ArticleConstants.HOT_ARTICLE_LIKE_WEIGHT;
        }
        if (apArticle.getViews() != null) {
            score += apArticle.getViews();
        }
        if (apArticle.getComment() != null) {
            score += apArticle.getComment() * ArticleConstants.HOT_ARTICLE_COMMENT_WEIGHT;
        }
        if (apArticle.getCollection() != null) {
            score += apArticle.getCollection() * ArticleConstants.HOT_ARTICLE_COLLECTION_WEIGHT;
        }

        return score;
    }
}